use super::super::domain::{
    account::AccountDao,
    user::{UserDao, UserRole},
};
use super::super::PrimaryKey;
use crate::prelude::*;
use sqlx::{query_as, Encode, Executor, MySql, Type};
pub async fn find_one_user_by_id<'e, 'c: 'e, E, T, P>(id: T, e: E) -> AppResult<UserDao>
where
    T: PrimaryKey<P>,
    for<'a> P: 'a + Encode<'a, MySql> + Type<MySql> + Send,
    E: 'e + Executor<'c, Database = sqlx::MySql>,
{
    let sql = format!("SELECT * FROM {} where id=?", UserDao::get_table_name());
    let id_pk = id.get_pk();
    let u: UserDao = query_as::<_, UserDao>(&sql)
        .bind(id_pk)
        .fetch_one(e)
        .await?;
    Ok(u)
}

pub async fn find_accounts_by_user<'e, 'c: 'e, E, T, P>(pk: T, e: E) -> AppResult<Vec<AccountDao>>
where
    T: PrimaryKey<P>,
    for<'a> P: 'a + Encode<'a, DBType> + Type<DBType> + Send,
    E: 'e + Executor<'c, Database = DBType>,
{
    let pk = pk.get_pk();
    let sql = format!(
        "SELECT * FROM {account} WHERE id=?",
        account = AccountDao::get_table_name()
    );
    let accounts: Vec<AccountDao> = query_as::<_, AccountDao>(&sql)
        .bind(pk)
        .fetch_all(e)
        .await?;
    Ok(accounts)
}
pub async fn find_user_role<'e, 'c: 'e, E, T, P>(user_pk: T, e: E) -> AppResult<i32>
where
    T: PrimaryKey<P>,
    for<'a> P: 'a + Encode<'a, DBType> + Type<DBType> + Send,
    E: 'e + Executor<'c, Database = DBType>,
{
    let user_pk = user_pk.get_pk();
    let sql = format!(
        "SELECT role FROM {user_role} WHERE user_id=?",
        user_role = UserRole::get_table_name()
    );
    let roles: Vec<(i32,)> = query_as(&sql).bind(user_pk).fetch_all(e).await?;
    Ok(roles
        .iter()
        .map(|(val,)| *val)
        .reduce(|prev, curr| prev | curr)
        .unwrap_or(1))
}
// pub async fn expand_user(dao:&UserDao) {

// }

#[cfg(test)]
mod tests {
    use super::*;

    #[actix_rt::test]
    async fn test_find_on_user_by_id() {
        crate::db_init!().await;

        println!("{:?}", find_one_user_by_id(1, crate::get_db_pool!()).await);
    }
    #[actix_rt::test]
    async fn test_transaction_find_user_by_id() {
        crate::db_init!().await;
        let mut trans = crate::get_db_pool!().begin().await.unwrap();
        let t = auto_reject!(trans, async {
            let v = find_one_user_by_id(1, &mut trans).await;
            if let Ok(v) = v {
                let b = find_one_user_by_id(2, &mut trans).await;
                if let Ok(b) = b {
                    Ok((Some(v), Some(b)))
                } else {
                    Ok((Some(v), None))
                }
            } else {
                Err(v.unwrap_err())
            }
        });
        println!("{:?}", t);
    }
    #[actix_rt::test]
    async fn test_find_accounts_by_user() {
        crate::db_init!().await;
        println!(
            "{:?}",
            find_accounts_by_user(1, crate::get_db_pool!()).await
        )
    }
}
